package com.apes.fn.rpt.settle.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.rpt.profit.GrossProfitService;
import com.apes.fn.rpt.settle.model.IncomeSummary;
import com.apes.fn.rpt.settle.repository.IncomeSummaryRepository;
import com.apes.fn.rpt.settle.repository.SummaryDao;
import com.apes.fn.scm.merchant.account.repository.AccountSettlementRepository;
import com.apes.fn.scm.merchant.account.repository.MerchantFixedLossRepository;
import com.apes.fn.scm.merchant.settlement.repository.MerchantSettlementDao;
import com.apes.fn.scm.merchant.settlement.service.FeeRateService;
import com.apes.fn.scm.retailOrder.repository.ReportDaliyDao;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * @author pengyb
 */
@Service("incomeSummaryService")
public class IncomeSummaryService extends DomainService {

    @Autowired
    private EnumerationRepository enumerationRepository;

    @Autowired
    private SummaryDao summaryDao;

    @Autowired
    private PartyRoleRepository partyRoleRepository;

    @Autowired
    private MerchantSettlementDao merchantSettlementDao;

    @Autowired
    private FeeRateService feeRateService;

    @Autowired
    private IncomeSummaryRepository incomeSummaryRepository;


    /**
     * 生成报表
     *
     * @param request
     */
    private void generate(SimpleRequest request) {
        //获取日期
        Date date = DateUtil.dateToDate(request.getJO().getDate("taskDate"), DateUtil.SHOW_DATE_FORMAT);
        //获取营业收入枚举
        List<Enumeration> incomeSummaries = enumerationRepository.findAll(JpaDsl.toCriteriaByEq("type.id", "incomeSummary", "valid", 1));

        summaryDao.queryIncome(date, date).forEach(result -> {
            PartyRole company = partyRoleRepository.findOne((String) result.get("COMPANY_ID"));
            processing(incomeSummaries, result, company, date);

        });

    }

    /**
     * 批量生成
     *
     * @param request
     */
    public void batchGenerate(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        Date startDate = DateUtil.dateToDate(requestJO.getDate("startDate"), DateUtil.SHOW_DATE_FORMAT);
        Date endDate = DateUtil.dateToDate(requestJO.getDate("endDate"), DateUtil.SHOW_DATE_FORMAT);
        //获取营业收入枚举
        List<Enumeration> incomeSummaries = enumerationRepository.findAll(JpaDsl.toCriteriaByEq("type.id", "incomeSummary", "valid", 1));

        summaryDao.queryIncome(startDate, endDate).forEach(result -> {
            PartyRole company = partyRoleRepository.findOne((String) result.get("COMPANY_ID"));
            Date statisticsDate = DateUtil.parse(result.get("DATE_OF_STATISTICS").toString());
            processing(incomeSummaries, result, company, statisticsDate);

        });
    }

    /**
     * 根据收入项目处理数据
     *
     * @param incomeSummaries
     * @param result
     * @param company
     * @param statisticsDate
     */
    private void processing(List<Enumeration> incomeSummaries, Map result, PartyRole company, Date statisticsDate) {
        incomeSummaries.forEach(enumeration -> {
            Double amount = Double.valueOf(result.get(enumeration.getCode()).toString());
            IncomeSummary incomeSummary = incomeSummaryRepository.findOne(
                    JpaDsl.toCriteriaByEq("company.id", company.getId(), "statisticsDate", statisticsDate, "incomeType.id", enumeration.getId())).orElse(new IncomeSummary());
            buildIncomeSummary(company, statisticsDate, enumeration, amount, incomeSummary);
        });
    }

    /**
     * 构建收入汇总报表
     *
     * @param company
     * @param statisticsDate
     * @param enumeration
     * @param amount
     * @param incomeSummary
     */
    private void buildIncomeSummary(PartyRole company, Date statisticsDate, Enumeration enumeration, Double amount, IncomeSummary incomeSummary) {
        incomeSummary.setIncomeType(enumeration);
        incomeSummary.setCompany(company);
        incomeSummary.setPaymentAmount(amount);
        incomeSummary.setStatisticsDate(statisticsDate);
        switch (enumeration.getCode()) {
            case "INTERNAL_DERATE":
            case "DERATE":
                incomeSummary.setPaymentAmount(0);
                incomeSummary.setPlatformManagementFee(amount * -1);
                break;
            case "LOSS_DERATE":
                //取基地定损减免平台服务费
                incomeSummary.setPaymentAmount(0);
                incomeSummary.setPlatformManagementFee(merchantSettlementDao.getLossAssessmentCostData(company.getId(), statisticsDate, statisticsDate).stream().map(
                                data ->
                                        (Double.parseDouble(data.get("TAX_COST_PRICE").toString()) * feeRateService.getPlatformRules(company.getId(), (Date) data.get("CREATE_DATE"))))
                        .reduce(Arith::add).orElse(0.0) * -1);
                break;
            default:
                incomeSummary.setPlatformManagementFee(amount * feeRateService.getPlatformRules(company.getId(), statisticsDate));
        }
        incomeSummary.setSettlementAmount(Arith.sub(incomeSummary.getPaymentAmount(), incomeSummary.getPlatformManagementFee()));
        incomeSummaryRepository.saveAndFlush(incomeSummary);
    }

    /**
     * 查询销售报表
     *
     * @param request
     * @return
     */
    public Map querySale(SimpleRequest request) {
        JSONObject queryCondition = parseQueryCondition(request);
        return packageReturnArray(summaryDao.querySale(queryCondition));
    }

    /**
     * 查询应收账款(内)明细
     *
     * @param request
     * @return
     */
    public JSONObject findReceivableInMx(SimpleRequest request) throws ParseException {
        JSONObject param = ((JSONObject) request.get("data")).getJSONObject("node");
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map DATE_OF_STATISTICS = MapUtil.mapper("field", "DATE_OF_STATISTICS",
                "headerName", "统计日期", "width", 110
        );
        tableHeader.add(DATE_OF_STATISTICS);
        Map DEPT_NAME = MapUtil.mapper("field", "DEPT_NAME",
                "headerName", "部门名称", "width", 220
        );
        tableHeader.add(DEPT_NAME);

        Map TYPE = MapUtil.mapper("field", "ACCOUNTTYPE",
                "headerName", "挂账类型", "width", 90
        );
        tableHeader.add(TYPE);
        Map api = MapUtil.mapper("api", "rcl.businessAmt.receivableInMxGdj");
        Map AMOUNT = MapUtil.mapper("field", "AMOUNT",
                "headerName", "营业额", "width", 130, "sum", true, "cellRenderer", "link", "cellEditorParams", api
        );
        tableHeader.add(AMOUNT);


        Map COMPANY_NAME = MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司名称", "width", 280
        );
        tableHeader.add(COMPANY_NAME);
        param.put("DATE_APPROVE", param.get("STATISTICS_DATE"));

        JSONArray array = SpringManager.getBean(ReportDaliyDao.class).find_receivableInMx(param);

        object.put("tableHeader", tableHeader);
        object.put("content", array);
        return object;
    }

    /**
     * 查询应收账款(外)明细
     *
     * @param request
     * @return
     */
    public JSONObject findReceivableOutMx(SimpleRequest request) throws ParseException {
        JSONObject param = ((JSONObject) request.get("data")).getJSONObject("node");
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map DATE_OF_STATISTICS = MapUtil.mapper("field", "DATE_OF_STATISTICS",
                "headerName", "统计日期", "width", 110
        );
        tableHeader.add(DATE_OF_STATISTICS);
        Map DEPT_NAME = MapUtil.mapper("field", "DEPT_NAME",
                "headerName", "部门名称", "width", 220
        );
        tableHeader.add(DEPT_NAME);
        Map api = MapUtil.mapper("api", "rcl.businessAmt.receivableOutMxGdj");
        Map AMOUNT = MapUtil.mapper("field", "AMOUNT",
                "headerName", "营业额", "width", 130, "sum", true, "cellRenderer", "link", "cellEditorParams", api
        );
        tableHeader.add(AMOUNT);


        Map COMPANY_NAME = MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司名称", "width", 280
        );
        tableHeader.add(COMPANY_NAME);

        Map CUSTOMER_NAME = MapUtil.mapper("field", "CUSTOMER_NAME",
                "headerName", "客户名称", "width", 280
        );
        tableHeader.add(CUSTOMER_NAME);
        param.put("DATE_APPROVE", param.get("STATISTICS_DATE"));
        JSONArray array = SpringManager.getBean(ReportDaliyDao.class).find_receivableOutMx(param);

        object.put("tableHeader", tableHeader);
        object.put("content", array);
        return object;
    }

    /**
     * 查询货币资金明细
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public JSONObject paymentMx(SimpleRequest request) throws ParseException {
        JSONObject param = ((JSONObject) request.get("data")).getJSONObject("node");
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map DATE_OF_STATISTICS = MapUtil.mapper("field", "DATE_APPROVE",
                "headerName", "统计日期", "width", 110
        );
        tableHeader.add(DATE_OF_STATISTICS);
        Map DEPT_NAME = MapUtil.mapper("field", "DEPT_NAME",
                "headerName", "部门名称", "width", 220
        );
        tableHeader.add(DEPT_NAME);

        Map TYPE = MapUtil.mapper("field", "PAYMENT_METHOD_TYPE_NAME",
                "headerName", "收款方式", "width", 90
        );
        tableHeader.add(TYPE);
        Map api = MapUtil.mapper("api", "rcl.businessAmt.paymentMxGdj");
        Map ZJ_AMT = MapUtil.mapper("field", "ZJ_AMT",
                "headerName", "货币资金（不含定损代收）", "width", 130, "sum", true, "cellRenderer", "link", "cellEditorParams", api
        );
        tableHeader.add(ZJ_AMT);
        Map AMOUNT = MapUtil.mapper("field", "AMOUNT",
                "headerName", "收款金额", "sum", "true", "width", 90
        );

        tableHeader.add(AMOUNT);
        Map DS_AMT = MapUtil.mapper("field", "DS_AMT",
                "headerName", "定损代收", "sum", "true", "width", 90
        );
        tableHeader.add(DS_AMT);

        Map COMPANY_NAME = MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司名称", "width", 280
        );
        tableHeader.add(COMPANY_NAME);
        param.put("DATE_APPROVE", param.get("STATISTICS_DATE"));
        JSONArray array = SpringManager.getBean(ReportDaliyDao.class).paymentMx(param);

        object.put("tableHeader", tableHeader);
        object.put("content", array);
        return object;
    }


    /**
     * 会员跨公司消费-收入
     *
     * @param request
     * @return
     */
    public Map findCrossCompanyIncome(SimpleRequest request) throws ParseException {
        JSONObject param = ((JSONObject) request.get("data")).getJSONObject("node");
        return packageReturnArray(SpringManager.getBean(ReportDaliyDao.class).findCrossCompanyIncome(param));
    }

    /**
     * 会员跨公司消费-支出
     *
     * @param request
     * @return
     */
    public Map findCrossCompanyPay(SimpleRequest request) throws ParseException {
        JSONObject param = ((JSONObject) request.get("data")).getJSONObject("node");
        return packageReturnArray(SpringManager.getBean(ReportDaliyDao.class).findCrossCompanyPay(param));
    }

    /**
     * 获取委托定损成本明细
     *
     * @param request
     * @return
     */
    public JSONObject findLossAssessmentCost(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject parseRequest = parseRequest(request, requestJO);
        List<Map> resultList = merchantSettlementDao.findLossAssessmentCost(parseRequest,
                parseRequest.getDate("reconcileBeginDate"), parseRequest.getDate("reconcileEndDate"), parseRequest.getIntValue("page"), parseRequest.getIntValue("size"));
        Object count = merchantSettlementDao.findLossAssessmentCostCount(parseRequest, parseRequest.getDate("reconcileBeginDate"), parseRequest.getDate("reconcileEndDate"));
        JSONObject object = new JSONObject();
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 获取平台服务费减免明细
     *
     * @param request
     * @return
     */
    public JSONObject findFeeReducedDetail(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject parseRequest = parseRequest(request, requestJO);
        List<Map> resultList = merchantSettlementDao.findFeeReducedDetail(parseRequest.getString("merchantId"),
                parseRequest.getDate("reconcileBeginDate"), parseRequest.getDate("reconcileEndDate"), parseRequest.getIntValue("page"), parseRequest.getIntValue("size"));
        Object count = merchantSettlementDao.findFeeReducedDetailCount(parseRequest.getString("merchantId"),
                parseRequest.getDate("reconcileBeginDate"), parseRequest.getDate("reconcileEndDate"));
        JSONObject object = new JSONObject();
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 获取内部销售明细
     *
     * @param request
     * @return
     */
    public JSONObject findInternalDetail(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject parseRequest = parseRequest(request, requestJO);
        List<Map> resultList = merchantSettlementDao.findInternalDetail(parseRequest.getString("merchantId"),
                parseRequest.getDate("reconcileBeginDate"), parseRequest.getDate("reconcileEndDate"), parseRequest.getIntValue("page"), parseRequest.getIntValue("size"));
        Object count = merchantSettlementDao.findInternalDetailCount(parseRequest.getString("merchantId"),
                parseRequest.getDate("reconcileBeginDate"), parseRequest.getDate("reconcileEndDate"));
        JSONObject object = new JSONObject();
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }


    /**
     * 解析请求
     *
     * @param request
     * @param requestJO
     * @return
     */
    public JSONObject parseRequest(SimpleRequest request, JSONObject requestJO) {
        int page = 0;
        int size = 50;
        if (requestJO.containsKey("data")) {
            requestJO = requestJO.getJSONObject("data");
            page = (int) request.getJO().get("page");
            size = (int) request.getJO().get("size");

        }
        requestJO.put("page", page);
        requestJO.put("size", size);
        JSONObject queryDate = parseQueryDate(request);
        requestJO.put("reconcileBeginDate", queryDate.getDate("reconcileBeginDate"));
        requestJO.put("reconcileEndDate", DateUtil.add(queryDate.getDate("reconcileEndDate"), Calendar.DAY_OF_MONTH, 1));
        requestJO.put("merchantId", requestJO.getJSONObject("node").get("COMPANY_ID"));
        if (requestJO.getJSONObject("node").get("COMPANY_ID") == null) {
            requestJO.put("merchantId", requestJO.getJSONObject("merchant").getString("id"));
        }
        return requestJO;
    }

    /***
     * 包装返回数据
     */
    private Map packageReturnArray(JSONArray array) {
        return MapUtil.mapper(
                "content", array,
                "total", array.size(),
                "size", array.size()
        );
    }

    /***
     * 解析查询条件
     */
    private JSONObject parseQueryCondition(SimpleRequest request) {
        JSONObject param = request.getJO();
        JSONObject queryCondition = new JSONObject();
        JSONObject data = param.getJSONObject("data");
        JSONObject rowData = data.getJSONObject("node");
        String sSQL = "";

        //检测是否是对账单跳转的
        if (data.containsKey("reconcileBeginDate")) {

            sSQL += " AND X.CREATE_DATE  < :STATISTICS_DATE_MAX +1 AND X.CREATE_DATE >= :STATISTICS_DATE_MIN";
            sSQL += " AND X.COMPANY_ID = :COMPANY_ID ";
            queryCondition.put("STATISTICS_DATE_MIN", data.getDate("reconcileBeginDate"));
            queryCondition.put("STATISTICS_DATE_MAX", data.getDate("reconcileEndDate"));
            queryCondition.put("COMPANY_ID", data.getJSONObject("merchant").getString("id"));
            queryCondition.put("SQL", sSQL);
            return queryCondition;
        }
        int showType = data.getIntValue("_showType");

        if (data.get("STATISTICS_DATE") != null && data.getJSONArray("STATISTICS_DATE").size() != 0) {
            queryCondition.put("STATISTICS_DATE_MIN",
                    parseDateString(data.getJSONArray("STATISTICS_DATE").getString(0)));
            queryCondition.put("STATISTICS_DATE_MAX",
                    parseDateString(data.getJSONArray("STATISTICS_DATE").getString(1)));

            // 拼接SQL
            if (showType == 0) {
                queryCondition.put("CREATE_DATE", rowData.getDate("STATISTICS_DATE"));
                sSQL += " AND X.CREATE_DATE  < :CREATE_DATE +1 AND X.CREATE_DATE >= :CREATE_DATE";
            } else if (showType == 1) {
                queryCondition.put("CREATE_DATE", rowData.getString("STATISTICS_DATE"));
                sSQL += SpringManager.getBean(GrossProfitService.class).contactSqlByMonth(queryCondition.getString("CREATE_DATE"),
                        queryCondition.getDate("STATISTICS_DATE_MIN"), queryCondition.getDate("STATISTICS_DATE_MAX"));
            } else {
                sSQL += " AND X.CREATE_DATE >= :STATISTICS_DATE_MIN  AND X.CREATE_DATE < :STATISTICS_DATE_MAX+1";
            }
        } else {
            throw new RuntimeException("查询其他关联数据时统计日期不允许为空");
        }

        if (rowData.containsKey("COMPANY_ID") && rowData.get("COMPANY_ID") != null) {
            sSQL += " AND X.COMPANY_ID = :COMPANY_ID ";
            queryCondition.put("COMPANY_ID", rowData.get("COMPANY_ID"));
        }
        queryCondition.put("SQL", sSQL);
        return queryCondition;
    }

    /***
     * 处理前端时间
     */

    private Date parseDateString(String str) {
        str = str.replace("Z", " UTC");//是空格+UTC
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");//格式化的表达式
        try {
            return format.parse(str);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /***
     * 解析日期
     * */
    public JSONObject parseQueryDate(SimpleRequest request) {
        JSONObject param = request.getJO();
        JSONObject queryCondition = new JSONObject();
        JSONObject data = param.getJSONObject("data");
        JSONObject rowData = data.getJSONObject("node");
        //检测是否是对账单跳转的
        if (data.containsKey("reconcileBeginDate")) {
            queryCondition.put("reconcileBeginDate", data.getDate("reconcileBeginDate"));
            queryCondition.put("reconcileEndDate", data.getDate("reconcileEndDate"));
            queryCondition.put("COMPANY_ID", data.getJSONObject("merchant").getString("id"));
            return queryCondition;
        }
        int showType = data.getIntValue("_showType");
        if (data.get("STATISTICS_DATE") != null && data.getJSONArray("STATISTICS_DATE").size() != 0) {
            queryCondition.put("reconcileBeginDate",
                    parseDateString(data.getJSONArray("STATISTICS_DATE").getString(0)));
            queryCondition.put("reconcileEndDate",
                    parseDateString(data.getJSONArray("STATISTICS_DATE").getString(1)));

            // 拼接SQL
            if (showType == 0) {
                queryCondition.put("reconcileBeginDate", rowData.getDate("STATISTICS_DATE"));
                queryCondition.put("reconcileEndDate", rowData.getDate("STATISTICS_DATE"));
            } else if (showType == 1) {
                Date reconcileBeginDate = queryCondition.getDate("reconcileBeginDate");
                Date reconcileEndDate = queryCondition.getDate("reconcileEndDate");
                String statistics_date = rowData.getString("STATISTICS_DATE");
                if (!DateUtil.format(reconcileBeginDate, "yyyy-MM")
                        .equals(DateUtil.format(reconcileEndDate, "yyyy-MM"))) {
                    if (statistics_date.equals(DateUtil.format(reconcileBeginDate, "yyyy-MM"))) {
                        queryCondition.put("reconcileEndDate", DateUtil.getMonthLastDay(reconcileBeginDate));
                        return queryCondition;
                    } else if (statistics_date.equals(DateUtil.format(reconcileEndDate, "yyyy-MM"))) {
                        queryCondition.put("reconcileBeginDate", DateUtil.getMonthFirstDay(reconcileEndDate));
                        return queryCondition;
                    } else {
                        Date date = DateUtil.parse(statistics_date + "-01");
                        queryCondition.put("reconcileBeginDate", DateUtil.getMonthFirstDay(date));
                        queryCondition.put("reconcileEndDate", DateUtil.getMonthLastDay(date));
                        return queryCondition;
                    }
                } else {
                    return queryCondition;
                }
            } else {
                return queryCondition;
            }
        } else {
            throw new RuntimeException("查询其他关联数据时统计日期不允许为空");
        }

        return queryCondition;
    }

    public com.apestech.framework.json.JSONObject internalHelpReturnQuery(SimpleRequest request) throws Exception {
        JSONObject jo = request.getJO();
        JSONArray condition = jo.getJSONArray("condition");
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String date = ((JSONObject) condition.get(1)).get("value").toString().substring(0, 10);
        if (date.equals(format)) throw new RuntimeException("该报表为次日统计报表，不可选择当天！！");
        if (condition != null) {
            for (int i = 0; i < condition.size(); i++) {
                if ("DATE_OF_STATISTICS".equals(condition.getJSONObject(i).getString("field"))) {
                    JSONObject json = new JSONObject();
                    if ("GTE".equals(condition.getJSONObject(i).getString("operator"))) {
                        json.put("field", "DATE_OF_STATISTICS_START");
                        json.put("operator", "EQ");
                        json.put("value", condition.getJSONObject(i).getString("value"));
                        json.put("type", "date");
                        condition.add(json);
                    } else if ("LTE".equals(condition.getJSONObject(i).getString("operator"))) {
                        json.put("field", "DATE_OF_STATISTICS_END");
                        json.put("operator", "EQ");
                        json.put("value", condition.getJSONObject(i).getString("value"));
                        json.put("type", "date");
                        condition.add(json);
                    }
                }
            }
            jo.put("condition", condition);
        }
        return com.apestech.framework.json.JSON.toJSON(jo.toJSONString());
    }

    /**
     * 获取定损未回款
     *
     * @param request
     * @return
     */

    public JSONObject fixedLoss(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        JSONObject parseRequest = parseRequest(request, requestJO);
        List<Map<String, String>> resultList = SpringManager.getBean(MerchantFixedLossRepository.class)
                .findCompanyDetail(parseRequest.getString("merchantId"),
                        parseRequest.getDate("reconcileBeginDate"),
                        parseRequest.getDate("reconcileEndDate"));
        JSONObject object = new JSONObject();
        object.put("content", resultList);
        object.put("total", resultList.size());
        return object;
    }
}
